﻿using System;
using System.Timers;
using Model01.Exceptions;
using Model01.Objects;

namespace Model01.Modifier
{
    /// <summary>
    /// Represents the streetlight that switches lights across given time interval.
    /// </summary>
    public class Streetlight : Model01.Objects.Object
    {
        #region Fields

        private Lights light;
        private int switchTime;
        private Timer timer; 
        private sbyte stat, curr;

        #endregion        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="switchTime">Time interbal between streetlight switching.</param>
        public Streetlight(int switchTime, int x, int y, Size size) : base(x, y, size)
        {
            timer = new Timer();
            SwitchTime = switchTime;            
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        }

        #region Methods

        /// <summary>
        /// Starts work of streetlight from green light.
        /// </summary>
        public void StartFromGreen()
        {
            curr = 2; stat = -1;
            timer.Start();
        }

        /// <summary>
        /// Starts work of streetlight from red light.
        /// </summary>
        public void StartFromRed()
        {
            curr = 0; stat = 1;
            timer.Start();
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            light = (Lights)curr;
            curr += stat;
            stat += (sbyte)((1 - curr) * 2);
            CurrentLight = light;
            NextLight = (Lights)curr;
            OnLightChange(this, new LihgtChangeEventArgs(CurrentLight, NextLight));
        }        

        #endregion

        #region Events

        /// <summary>
        /// Hapens when light of streetlight switches.
        /// </summary>
        public event OnLihgtChangeEvent OnLightChange = delegate { };

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets time interbal between streetlight switching.
        /// </summary>
        /// <exception cref="Model01.Exceptions.NonPositiveSwitchTimeException"/>
        public int SwitchTime
        {
            get { return switchTime; }
            set
            {
                if (value > 0)
                {
                    switchTime = value;
                    timer.Interval = value;
                }
                else
                    throw new NonPositiveSwitchTimeException();
            }
        }

        public Lights CurrentLight { get; private set; }

        public Lights NextLight { get; private set; }

        #endregion
    }

    /// <summary>
    /// Lights of streetlight.
    /// </summary>
    public enum Lights
    {
        Red,
        Yellow,
        Green
    }

    #region Description of event delegates and args

    public delegate void OnLihgtChangeEvent(object sender, LihgtChangeEventArgs e);
    
    public class LihgtChangeEventArgs : EventArgs
    {
        private readonly Lights light;
        private readonly Lights nextLight;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="light">Current light of Streetlight</param>
        /// <param name="nextLight">The next light of Streetlight</param>
        public LihgtChangeEventArgs(Lights light, Lights nextLight)
        {
            this.light = light;
            this.nextLight = nextLight;
        }

        public Lights Light
        {
            get { return light; }
        }

        public Lights NextLight
        {
            get { return nextLight; }
        }
    }

    #endregion
}
